using System;
using System.Collections;
using System.Html;
using System.Runtime.CompilerServices;
using Actors;
using Awaiter;
using Nsb.Classes;
using Yoshi.Classes;
using jQueryApi;

namespace YesPlayLove.Clusters
{
    [IgnoreNamespace]
    public class MagBubble : Cluster
    {
        private const int MonitorInterval = 7000;
        private static int _classCount;
        private readonly Await _awp;
        private readonly MagneticData _data;
        private string _className;
        private int _itemIndex;
        private jQueryObject _listItems;
        private string _listTitle = MagneticListTheme.BubbleTopic;
        private jQueryObject _magList;
        private jQueryObject _magName;
        private readonly Eyes _eyes;
        private static int _timer;

        public MagBubble(Await awp)
        {
            ClassName = "MagBubble" + (++_classCount);
            _awp = awp;
            _data = new MagneticData();
            _eyes = new Eyes().Flirting(true);
            _eyes.Element.AppendTo(Document.Body);
            Build();
        }

        public string ListTitle
        {
            get { return _listTitle; }
            set { _listTitle = value; }
        }

        private bool HasAnyItem
        {
            get
            {
                if (_itemIndex > 1)
                    return true;
                jQueryObject items = jQuery.Select(".MagItem");
                return items.Length > 0 && !String.IsNullOrEmpty(items.GetValue().Trim());
            }
        }

        private void Build()
        {
            _className = ClassName + "_Element";

            Element = jQuery.FromHtml("<div/>")
                .AddClass(_className)
                ;

            jQuery.Select(String.Format(".{0} .MagName, .{0} .MagItem", _className))
                .Live("keypress.maglist",
                      delegate(jQueryEvent e)
                      {
                          _data.Saved(false);
                          if (e.Which == 9 || e.Which == 13) // tab or ret
                          {
                              CancelEvent(e);
                              if (!jQuery.FromElement(e.Target).Is(".MagName"))
                                  SaveRecord();
                              AddDropGadget();
                              AddListButtons();
                              AddLastLine();
                          }
                          _data.UpdatePage();
                      }
                )
                .Live("focus.maglist",
                      delegate(jQueryEvent e)
                      {
                          //Inform.Trace("Focusing {0}[{1}]", e.Target.TagName, e.Target.TabIndex);
                          Master.Page.FocusEvent(e);
                          _eyes.MoveToElement(jQuery.FromElement(e.Target));
                      }
                )
                .Live("blur.maglist",
                      delegate(jQueryEvent e)
                      {
                          //Inform.Trace("Bluring {0}[{1}]", e.Target.TagName, e.Target.TabIndex);
                          Master.Page.FocusEvent(null);
                          _eyes.FollowMouse();
                          jQueryObject el = jQuery.FromElement(e.Target);
                          if (el[0].TagName.ToLowerCase() == "textarea")
                              el.Plugin<Jewl>().VertHtml();
                      }
                )
                ;

            jQuery.Select(String.Format(".{0} .MagName", _className))
                .Live("blur.magname",
                      delegate(jQueryEvent e)
                      {
                          jQueryObject target = jQuery.FromElement(e.Target);
                          Inform.Trace("Bluring {0}[{1}]", e.Target.TagName, e.Target.TabIndex);
                          Master.Page.FocusEvent(null);
                          _eyes.FollowMouse();

                          string xname = CleanName(target.Plugin<Jewl>().GetFValueString());
                          string magName = xname.ToLowerCase();
                          string recName = CleanName(_data.RecordName).ToLowerCase();

                          //
                          // Detect record name change
                          //
                          if (!String.IsNullOrEmpty(magName) && magName != recName)
                          {
                              if (_data.Records.ContainsKey(magName))
                              {
                                  //Script.Alert(String.Format("List with the name \"{0}\" already exists", xname));
                                  new Await()
                                      .AddFn(PutNewList, xname)
                                      .Commit();
                              }
                              else if (!String.IsNullOrEmpty(magName))
                              {
                                  new Await()
                                      .AddDx(
                                          delegate
                                          {
                                              _listItems.Empty();
                                              _itemIndex = 0;
                                          }
                                      )
                                      .AddFn(AddDropGadget)
                                      .AddFn(AddLastLine)
                                      .AddFn(AddListButtons)
                                      .Commit();
                              }
                          }
                      }
                )
                ;

            new Await()
                .AddAw(_data.LoadRecordsAw)
                .AddFn(StartNewList)
                .AddDx(
                    delegate
                    {
                        Window.ClearInterval(_timer);
                        _timer = Window.SetInterval(delegate { MonitorLoop(); }, MonitorInterval);
                    }
                )
                .Commit(_awp);
        }

        public void Destroy()
        {
            Window.ClearInterval(_timer);
            _timer = 0;
            jQuery.Select(String.Format(".{0} .MagName, .{0} .MagItem", _className))
                .Die("keydown.maglist")
                .Die("focus.maglist")
                .Die("blur.maglist")
                ;
            jQuery.Select(String.Format(".{0} .MagName", _className))
                .Die("blur.magname")
                ;
            _eyes.Destroy();
        }

        private void PutNewList(string name)
        {
            new Await()
                .AddFn(_data.LoadRecord, name)
                .HandleDl(Exceptions.BlobLoadError, Await.IgnoreAw)
                .AddFn(CreateListHead)
                .AddFn(CreateNodes)
                .AddFn(ReplaceList)
                .AddFn(AddLastLine)
                .AddFn(AddListButtons)
                .AddFn(_data.UpdatePage)
                .Commit();
        }

        private void StartNewList()
        {
            Inform.Trace("StartNewList()");
            new Await()
                .AddFn(_data.EmptyRecord)
                .AddFn(CreateListHead)
                .AddFn(ReplaceList)
                .AddFn(AddListButtons)
                .AddDx(delegate { _magName.Value("").Focus(); })
                .AddAw(ScrollInViewAw, _magName)
                .Commit();
        }

        private void AddLastLine()
        {
            jQueryObject item = jQuery.Select(".MagItem", Element).Last();
            if (item.Length == 0 || !String.IsNullOrEmpty(item.GetValue().Trim()))
                ScrollInViewAw(Await.AsyncAw, AddItem().Focus());
            else
                ScrollInViewAw(Await.AsyncAw, item.Focus());
        }

        private void ReplaceList()
        {
            Inform.Trace("ReplaceList()");
            Element.Empty().Append(_magList);
            AddDropGadget();
        }

        private void CreateListHead()
        {
            //Inform.LogFn(Script.Literal("arguments"));
            //Inform.Trace("CreateListHead()");

            _itemIndex = 0;

            // Create the list
            _magName = jQuery.FromHtml("<input class='MagName' type='text' tabindex='1'/>");
            _listItems = jQuery.FromHtml("<ol id='MagList'/>");
            _magList = jQuery.FromHtml("<div id='MagneticList' class='MagneticList'/>")
                .Append(_magName)
                .Append(_listItems)
                ;

            if (Script.IsValue(_data.DataRecord))
            {
                Inform.Trace("-- Putting existing record");
                _magList.Prepend(jQuery.FromHtml("<div class='MagTitle'/>").Html(_listTitle));
                _magName.Plugin<Jewl>().FValueString(_data.RecordName);
            }
            else
            {
                Inform.Trace("-- Putting new record");
                _magList.Prepend(jQuery.FromHtml("<div class='MagTitle'/>").Html("New - " + _listTitle));
            }
        }

        private void CreateNodes()
        {
            _itemIndex = 0;

            if (Script.IsNullOrUndefined(_data.RecordName))
                return;

            // Create the list
            foreach (string item in _data.DataRecord.items)
            {
                if (item.Trim().Length > 0)
                {
                    jQueryObject i = AddItem();
                    i.Plugin<Jewl>().FValueString(item);
                }
            }
        }

        private jQueryObject AddItem()
        {
            jQueryObject item = jQuery.FromHtml("<li/>");
            jQueryObject input = jQuery.FromHtml("<textarea class='MagItem'/>")
                .AppendTo(item)
                .Attribute("tabindex", (_itemIndex + 2).ToString())
                ;
            jQuery.FromHtml("<span class='MagItemDelete'/>")
                .AppendTo(item)
                .Html("x")
                .Click(
                    delegate
                    {
                        item.Remove();
                        SaveRecord();
                    }
                )
                .Attribute("title", MagneticListTheme.DeleteItemTitle)
                ;

            _listItems
                .Append(item)
                ;

            _itemIndex++;
            return input;
        }

        private void AddListButtons()
        {
            jQuery.Select(".MagDelete").Remove();
            jQuery.Select(".MagNew").Remove();
            if (HasAnyItem)
            {
                // Add optional delete & new buttons
                jQuery.FromHtml("<span class='MagDelete'/>")
                    .InsertBefore(_listItems)
                    .Html("delete")
                    .Attribute("title", MagneticListTheme.DeleteListTitle)
                    .Click(
                        delegate
                        {
                            new Await()
                                .AddAw(new Ask().OkCancelAw,
                                       new Dictionary(
                                           "Message", String.Format("Delete {0} for sure?", _data.RecordName),
                                           "Title", "",
                                           "OkFace", "Oh Yea!"
                                           ))
                                .AddAw(RequireResultAw, true)
                                .AddFn(_data.UpdatePage)
                                .AddFn(_data.DeleteList, _data.RecordName)
                                .AddFn(StartNewList)
                                .Commit();
                        });
            }

            if (_data.Records.Count > 0 && !String.IsNullOrEmpty(_magName.GetValue().Trim()))
            {
                jQuery.FromHtml("<span class='MagNew'/>")
                    .InsertBefore(_listItems)
                    .Html("new")
                    .Attribute("title", MagneticListTheme.NewListTitle)
                    .Click(
                        delegate
                        {
                            new Await()
                                .AddFn(SaveRecord)
                                .AddFn(_data.EmptyRecord)
                                .AddFn(StartNewList)
                                .Commit();
                        });
            }
        }

        private void SaveRecord()
        {
            if (HasAnyItem)
                _data.SaveRecord();
        }

        private void AddDropGadget()
        {
            new Await()
                .AddDx(delegate
                       {
                           Dictionary names = _data.NameList();
                           if (names.Count > 0)
                               new EyeFocusDropMenu(
                                   _magName,
                                   names,
                                   delegate(jQueryEvent ee, string postName)
                                   {
                                       new Await()
                                           .AddFn(SaveRecord)
                                           .AddFn(PutNewList, postName)
                                           .Commit();
                                   },
                                   _eyes
                                   );
                       })
                .Commit();
        }

        private void MonitorLoop()
        {
            Inform.Trace("MonitorLoop");
            if (!Master.Page.IsFocused(jQuery.Select(".MagName", Element)))
            {
                if (!_data.Saved())
                    SaveRecord();
                else
                    _data.UpdatePage();
            }
        }
    }
}